/*
 * Copyright (c) 2012 Universidad Antonio de Nebrija.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Apache License v2.0
 * which accompanies this distribution, and is available at
 * http://www.apache.org/licenses/LICENSE-2.0.html
 * 
 * Contributors:
 *    Universidad Antonio de Nebrija - initial API, implementation and documentation
 */
package com.nebrija.riif.model.saver.bufferedwriter;

import java.io.BufferedWriter;
import java.io.IOException;
import java.util.HashMap;

import com.nebrija.riif.model.ChildComponentList;
import com.nebrija.riif.model.ChildComponentUnit;
import com.nebrija.riif.model.RIIFElement;
import com.nebrija.riif.model.RIIFProperties;
import com.nebrija.riif.model.saver.ChildComponentListSaver;
import com.nebrija.riif.model.saver.RIIFSaverFactory;

/**
 * Implementation of an ChildComponentListSaver that writes the object to a BufferedWriter
 * @author asanchep
 *
 */
public class ChildComponentListWriterFormatSaver implements
		ChildComponentListSaver {

	/** Writer where the information about the object is sent */
	private BufferedWriter out;
	/** Factory used to create other elements of the saver family */
	private RIIFSaverFactory factory;

	/**
	 * Creates an ChildComponentListWriterFormatSaver
	 * @param out Writer where the information about the object is sent
	 * @param factory Factory used to create other elements of the saver family
	 */
	public ChildComponentListWriterFormatSaver(BufferedWriter out,
			RIIFWriterFormatSaverFactory factory) {
		this.out=out;
		this.factory=factory;
	}

	@Override
	public void save(ChildComponentList element) {
		if(out==null){
			return;
		}
		try{
			// If the list depends on a constant, retrieve the constant name, otherwise, retrieve the number of children
			String val = (element.getConstantDependantSize()!=null)?element.getConstantDependantSize():String.valueOf(element.getChildCount());
			out.append(ChildComponentUnitWriterFormatSaver.CHILD_COMPONENT_TOKEN).append(" ")
					.append(element.getImplementedComponentName())
					.append(" ").append(element.getName()).append("[1:").append(val).append("];\n");
			
			
			// Properties which have a common value throughout the whole array
			HashMap<String, Object> commonVars = new HashMap<String,Object>();
			HashMap<String, Object> commonVarsAfter = new HashMap<String,Object>();
			
			// Traverse all the children to check which variables have the same value and can be written in a summarized form
			for(int i=0; i<element.getChildCount(); i++){
				ChildComponentUnit ccu = element.getChild(i);
				HashMap<String,RIIFElement> props = ccu.getElements();
				for(String key:props.keySet()){
					RIIFElement subelement = props.get(key);
					if(!(subelement instanceof RIIFProperties)){
						continue;
					}
					RIIFProperties prop = (RIIFProperties) subelement;
					if(i==0){
						// We add all the properties from the first child 
						commonVarsAfter.put(subelement.getName(), prop.getValue());
					}else{
						// If the value of the property does not exist in the common variable array then ignore it
						Object value = commonVars.get(subelement.getName());
						if (value==null){
							continue;
						}
						// Populate the new array with the property values which match the values from the commonVars array  
						if(value.equals(prop.getValue())){
							commonVarsAfter.put(subelement.getName(), prop.getValue());
						}
					}
					
				}
				//flip the arrays
				HashMap<String,Object> aux = commonVars;
				commonVars=commonVarsAfter;
				commonVarsAfter=aux;
				// clear the commonVarsAfter array to reuse it
				commonVarsAfter.clear();
				// If there are no more common variables remaining, exit
				if(commonVars.size()<1){
					break;
				}
			}
			
			// Common variables are printed in the short syntax assign form
			for(String key:commonVars.keySet()){
				out.append(RIIFPropertiesWriterFormatSaver.ASSIGN_TOKEN).append(" ")
					.append(element.getName()).append("'").append(key).append("[1:").append(val).append("] = ")
					.append(commonVars.get(key).toString()).append(";\n");
			}
			
			// Specific properties for a child_component are printed for that child
			for(int i=0; i<element.getChildCount(); i++){
				ChildComponentUnit ccu = element.getChild(i);
				HashMap<String,RIIFElement> props = ccu.getElements();
				for(String key:props.keySet()){
					RIIFElement subelement = props.get(key);
					if(!(subelement instanceof RIIFProperties)){
						continue;
					}
					if (commonVars.containsKey(subelement.getName())){
						continue;
					}
					Object resObj = ((RIIFProperties)subelement).getValue();
					String res = (resObj==null)?"":resObj.toString();
					out.append(RIIFPropertiesWriterFormatSaver.ASSIGN_TOKEN).append(" ")
						.append(element.getName()).append("'").append(key)
						.append("[").append(String.valueOf(i+1)).append("] = ")
					.append(res).append(";\n");				
				}
			}
			out.append("\n");
			out.flush();
		}catch(IOException ioe){
			ioe.printStackTrace();
		}
		

	}

}
